前端基础

吴龙淼 写于 2021-08-29

目录

2. html,web基础
3. css
4. js
5. 正则表达式
6. vue,react

html,web 基础

HTMl 常用转义字符

space空格            
半个中文空格	     
中文空格	             
<                   &lt;
>	                &gt;
&	         &amp;
" 	         &quot;
'	         &apos;
©	         &copy;

js 转义字符

\n      换行
\t      tab
\r      回车符
\\      反斜杠
\u         unicode编码

js 真值表

[] '' 0 false  ==
{} !== every
NaN !== every
(-)Infinity === (-)Infinity
[] != []

js 运算符优先级(高到低)

. [] ()
++ -- ! delete new typeof
* / %
+ -
< <= => > instanceof
== !== === !=
位运算
&&
||
?:
=

meta

name属性主要用于描述网页,对应属性是 content ,以便于搜索引擎机器人查找、分类

A. keywords(关键字)
说明:用于告诉搜索引擎,你网页的关键字

B. description(网站内容的描述)
说明:用于告诉搜索引擎,你网站的主要内容

C. viewport(移动端的窗口)
<meta name="viewport" content="width=device-width, initial-scale=1">

D. robots(定义搜索引擎爬虫的索引方式)
说明:robots用来告诉爬虫哪些页面需要索引,哪些页面不需要索引。
具体参数如下:
1.none : 搜索引擎将忽略此网页,等价于noindex,nofollow。
2.noindex : 搜索引擎不索引此网页。
3.nofollow: 搜索引擎不继续通过此网页的链接索引搜索其它的网页。
4.all : 搜索引擎将索引此网页与继续通过此网页的链接索引,等价于index,follow。
5.index : 搜索引擎索引此网页。
6.follow : 搜索引擎继续通过此网页的链接索引搜索其它的网页。

E. author(作者)
说明:用于标注网页作者

F. generator(网页制作软件)
说明:用于标明网页是什么软件做的

G. copyright(版权)
说明:用于标注版权信息

H. revisit-after(搜索引擎爬虫重访时间)
说明:减轻搜索引擎爬虫对服务器带来的压力,设置爬虫的重访时间

Unicode 编码

万国码:全世界所有的语言、公式、符号
编码范围:0x000000-0x10FFFF  3个字节——24位
UTF-8:通过规则转换后再存储,变字长编码,前0x7f字符与ASCII码兼容
UTF-16:2字节存储,js字符串编码方式
	UTF-16BE大端就是将高位的字节放在低地址表示
	UTF-16LE小端就是将高位的字节放在高地址表示
UTF-32:使用4个字节存储,直接存码值,很多情况下是浪费内存的

ES6用\u表示unicode-32编码

cookie,session,localStorage 区别

为了弥补http/https协议无状态(不知道上次浏览器的操作)的缺陷,增加本地缓存

cookie 第一次请求后,后端响应头设置cooKie,以后作为HTTP请求响应头的一部分,
自定义保存时间,长度和数量的限制4k
sessionstorage 浏览器关闭删除数据5m,安全性高些,不用担心被截取
localStorage 除非用户删除数据5m,否则会一直存在本地,不用担心被截取
session 数据保存在服务器,安全性高,对服务器性能要求更高

前端性能优化方法

网络请求优化:
减少http请求(防抖节流;接口聚合)
gzip,Brotli压缩资源(无损压缩,服务器增加压力)
充分利用缓存,强缓存,协商缓存
减少域名数,cdn加速静态资源

渲染优化:
减少浏览器重绘回流次数,减少对doM的添加删除操作,使用transform,opcitiy 文档碎片
事件代理
多情况判断用hash表代替ifelse
利用垃圾回收,频繁回收的对象用对象池管理(其他自动回收的高级语言)

requestIdleCallback js线程空闲时执行(非关键的日志记录,ui更新,预加载资源)

Web Workers 独立线程执行复杂计算(如视频、图像裁剪,复杂数学计算,大数据处理,长时间运行的任务)
main.js (主线程):
// 创建Worker
const worker = new Worker('worker.js');
// 监听Worker消息
worker.onmessage = (e) => {
  console.log(`Fibonacci result: ${e.data}`);
};
// 发送计算任务
worker.postMessage(40); // 计算第40个斐波那契数
// 主线程不会被阻塞
console.log('Main thread continues to run...');

worker.js (Worker线程):
// 监听主线程消息
onmessage = function(e) {
  const n = e.data;
  const result = fibonacci(n);
  postMessage(result);
};

// 计算密集型函数
function fibonacci(n) {
  if (n <= 1) return n;
  return fibonacci(n - 1) + fibonacci(n - 2);
}

vue keep-alive v-memo    react.memo

webpack构建工具优化:
构建过程:  sourcemap  多线程构建,缓存loader  构建体积webpack-bundle-analyzer
压缩包大小优化: gzip,静态资源压缩插件  tree-sharking优化
性能优化: 模块懒加载splitChunk

单页应用首屏优化: 预渲染(骨架屏)
服务端渲染SSR: 优化首屏性能

react,vue

异同:
都是数据驱动
react单向数据流,vue非严格单向数据流
设计理念不同,react函数式,数据不可变,改变状态重新渲染整个组件树;vue基于依赖收集,更新粒度更细
react心智负担大,vue自动收集依赖

react踩坑:重复渲染,react18之前只有合成事件副作用是批量处理状态;闭包陷阱

vue踩坑: vue2对象删除添加,数组下标改变数据无响应式
         vue3 props,reactive基本类型解构失去响应式

http1,2,3

http1.0
队头阻塞(高延迟),并发请求限制4-8,一个请求被阻塞时,在后面排所有请求也被阻塞
无状态(无cookie,上一次请求验证了用户名密码,下一次请求服务器不知道有何关联)
明文传输

http2 谷歌SPDY
多路复用,无并发限制,只要带宽足够(请求阻塞时,请求优先级高的先被处理)
cookie(跨域设置withCredentials Access-Control-Allow-Origin Access-Control-Allow-Credentials)
支持加密tls/ssl(https)
head头压缩,请求和响应只发送差异部分
服务端推送,让服务端主动把资源文件推送给客户端。当然客户端也有权利选择是否接收。

事实上的http2==https,各大浏览器厂商只支持经加密的http2
(丢包情况严重,速度还不如http1,丢包重传机制)

http3 谷歌quic
基于udp,解决了丢包阻塞
拥塞控制,数据包重传

HTTP 请求过程

DNS域名解析
客户机提出域名解析请求,请求发送给本地的域名服务器。
本地域名服务器查询本地的缓存,如果有该纪录项,本地的域名服务器就直接把查询的结果返回。
如果本地的缓存中没有该纪录,则本地域名服务器就直接把请求发给根域名服务器,根域名服务器再返回给本地域名服务器一个查询域(根的子域) 的主域名服务器的地址。
本地服务器再向上一步返回的域名服务器发送请求,然后接受请求的服务器查询自己的缓存,如果没有该纪录,则返回相关的下级的域名服务器的地址。
本地域名服务器把返回的结果保存到缓存,结果返回给客户机。

根据IP建立TCP连接(三次握手)

发起HTTP请求
请求行(描述客户端的请求方式,url和http协议的版本号)
请求头(referer,origin,cookie,connection,accept,authorizaiton,accept-encoding,,host,warning,user-agent,content-type,date
cache-control:no-store禁用缓存;no-cache禁止强缓存;private禁止中间代理缓存;public允许中间代理缓存;max-age最大缓存时间;must-revalidate:在缓存过期前可以使用,过期后必须向服务器验证,不适用协商缓存
pragma:no-cache禁止强缓存,优先级最高
(ETag)if-none-match > (Last-Modified)if-modified-since 协商缓存
)
请求正文/数据(post请求,需要传递的数据传递到这)
简单请求:
head   仅请求响应首部
get 通过url传递,所以传输数据小1024,安全性低,仅查询,不做修改     常用于请求一个资源
post 安全,没有传输限制,可修改   提交表单
非简单请求:
delete 删除
put 更新

服务器处理请求,浏览器接收HTTP响应
状态行(协议版本,状态码200,状态码描述ok)
响应头(content-type,content-length,content-encoding,Content-Language,
date,server,vary,cache-control,etag,last-modified,expires,pragma)
响应数据/正文

渲染页面:
浏览器将获取的HTML文档并解析成DOM树。
css构成层叠样式表模型CSSOM(CSS Object Model)
将DOM和CSSOM合并为渲染树(rendering tree)
浏览器布局 绘制页面

关闭TCP连接(四次挥手)

xss 攻击(跨站脚本攻击)

注入恶意代码到网页,用户加载并执行
危害:盗用cookie
预防:
    过滤html,js,css标签,前后端转义& < > / ' "
    尽量避免.innerHTML、.outerHTML、document.write()
    dom内联事件,定时器,<a>不拼接不可信数据(过滤javascript:)
    后端设置http-only-cookie

csrf 攻击(跨站请求伪造攻击)

受害者登录a.com,并保留了登录凭证(Cookie)。
攻击者引诱受害者访问了b.com。
b.com 向 a.com 发送了一个请求:a.com/act=xx。浏览器会…
a.com接收到请求后,对请求进行验证,并确认是受害者的凭证,误以为是受害者自己发送的请求。
a.com以受害者的名义执行了act=xx。
攻击完成,攻击者在受害者不知情的情况下,冒充受害者,让a.com执行了自己定义的操作。
常见攻击方式: img,一个自动提交的表单,链接类型

预防:
    后端生成验证码,向手机发送验证码,或者再输入一次密码,后端再做一次验证
    验证请求头referer,Origin字段: 只能防御跨域请求,对于攻击者本域有权限,无法防范
    验证token(服务器生成由随机字符串,时间戳组合的token传给前端,并在后端session存储token,前端每次请求时把token传回,后端验证是否被篡改)
    双重cookie(后端生成token放入cookie,请求时提交一个cookie的值加入url参数或者放入请求头authorization,csrf无法获得具体的cookie值)

sql 注入攻击

利用程序漏洞,sql拼接,执行恶意代码(获取,篡改数据库数据)
防范:数据类型,格式检查;数据过滤

ddos 攻击

短时间内发起大量请求,耗尽服务器的资源,无法响应正常的访问
防范:请求过滤

同源策略

Cookie、LocalStorage 和 IndexDB 无法读取 DOM 无法获得。 AJAX 请求不能发送。

仅同域名,同端口,同协议的网页可以通讯,无法读取非同源网页的 Cookie、LocalStorage,无法向非同源地址发送 AJAX 请求

跨域请求

websocket服务器允许,客户端可以从不同的源建立WebSocket连接


html标签提交表单不受同源限制


img,link,js脚本标签


CORS:
    前端设置withCredentials选项,允许跨域请求携带cookie等敏感信息
    后端设置Access-Control-Allow-Origin Access-Control-Allow-Credentials


jsonp:只能发送get请求,一般用计时器来决定是否放弃等待响应
function handleResponse(response) {
 console.log(`You're at IP address ${response.ip});
}
//客户端请求
let script = document.createElement("script");
script.src = "http://freegeoip.net/json/?callback=handleResponse";
document.body.insertBefore(script, document.body.firstChild);


子域设置相同的document.domain,共享cookie,iframe
window.frames[name].window 获取所有的iframe
iframe.contentWindow, 获取iframe的window对象
iframe.contentDocument, 获取iframe的document对象
const iframe = document.querySelector("iframe").contentWindow;
iframe.document.querySelector("body").style.backgroundColor = "blue";

postMessage()
//http://main.com
`<iframe src="http://child.com" name="sendMessage"></iframe>`

//发送信息给其他窗口,必须引用非本窗口对象(iframe,window.open)
let ifr = window.frames['sendMessage'];
ifr.postmessage('main send message to child', "http://child.com");

window.addEventListener('message', receiver, false);
e.source – 消息源,消息的发送窗口/iframe。
e.origin – 消息源的 URl(可能包含协议、域名和端口),用来验证数据源。
e.data – 发送过来的数据。
function receiver(e) {
    if (e.origin == 'http://child.com') {
        if (e.data == 'child message') {
            e.source.postMessage('receive message', e.origin);  //向原网页返回信息
        }
    }
}

//http://child.com
window.onmessage = function(e) {
  if (e.origin !== 'http://main.com') {
    console.log('非可信!')
    return;
  }
  e.source.postMessage('child message',e.origin)
};

浏览器

主进程(管理子进程及书签前进后退等功能)
网络进程
gpu进程

渲染进程(一般一个标签一个进程)
    gui渲染线程
    js引擎线程
    http请求线程
    事件线程
    定时器线程
    worker子线程

互斥: js和渲染线程(js能操作dom,渲染前后容易不一致,处理麻烦)

css

常用宽高

dom对象:
只读属性
clientHeight clientWidth:padding+content
offsetHeight offsetWidth:padding+content+border
offsetTop offsetLeft:与最近父元素的top left
scrollHeight scrollWidth:元素宽高包括滚动条,若无滚动条===client

可写属性
scrollTop scrollLeft:滚动条的宽高left,top


window对象:
innerWidth innerHeight 浏览器窗口可视区域
outerWidth outerHeight 浏览器包括工具栏,滚动条
pageXOffset pageYOffset 相对浏览器窗口左上角xy位置
screenLeft screenTop screenX screenY 相对屏幕窗口xy坐标

事件对象常用属性

event.xxx
currentTarget 处于当前事件流的对象
target 触发事件的dom对象  (target.tagName)
clientX clientY 事件触发时鼠标相对浏览器坐标
pageX pageY 事件触发时鼠标相对浏览器坐标(包括滚动条)
screenX screenY 事件触发时鼠标相对屏幕窗口坐标
charCode 键盘事件代码,仅keypress
keyCode 键盘事件代码,keypress返回unicode, keydown,keyup返回键盘代码
which 键盘事件代码,keypress返回unicode, keydown,keyup返回键盘代码
key  键盘事件实际字符
shiftKey(boolean) shift是否被按下,所有事件都会监听
ctrlKey(boolean) ctrl是否被按下,所有事件都会监听
altKey(boolean) alt是否被按下,所有事件都会监听
metaKey(boolean) meta(window窗口)是否被按下,所有事件都会监听

preventDefault() 取消事件默认行为
stopPropagation() 取消冒泡

css 编写顺序

定位属性
自身属性
文本属性
其他属性

前端布局

静态(默认)布局
    网页外层容器有固定的大小,所有的内容以该容器为标准,超出宽高的部分用滚动条

自适应布局
	屏幕大小改变时,会出现不同的布局,由多个静态布局组成,只改变位置,大小不变

响应式布局
	媒体查询,根据不同设备适配
  @media (min-height: 680px), screen and (orientation: portrait) {}

弹性布局 flex
容器属性
flex-flow: flex-direction flex-wrap
flex-direction(改变主轴方向,默认是水平方向,交叉轴默认垂直方向):row(默认值) column  -reverse
flex-wrap:wrap nowrap(默认值)	wrap-reverse
justify-content(主轴):flex-start(默认值) flex-end center space-around  space-between
align-items(交叉轴):stretch(默认值) flex-start flex-end center  baseline
align-content(多条轴线):多行的对齐,单行无作用 stretch(默认值) flex-start flex-end center space-around  space-between

项目属性
align-self设置具体的项目,覆盖align-items flex-start flex-end center stretch baseline

order:0->n 优先级变小

flex
flex-grow:0(默认值,不放大)  数值越大,越放大
flex-shrink:1(默认值,空间不足缩小) 数值越大,越缩小
flex-basis在分配多余空间之前,项目占据的主轴空间
flex: flex-grow flex-shrink flex-basis

columns: 180px 3

两种盒子模型

标准盒子模型: width=content   元素padding,margin,border单独计算
ie盒子模型: width=content+padding+border

切换 box-sizing:content-box(默认值)  border-box

csshock

多浏览器兼容
在css样式中给不同浏览器加入特殊符号(比如:_ *只有ie识别)
是一种不推荐的兼容方案

行内元素,行内块元素,块元素

行内元素(内联元素):设置宽高无效,可以设置水平margin,padding,
默认高宽是自身内容高宽,不能放块标签
a label span
例外:a可以放除a外的标签

行内块元素:能设置宽高,margin,padding
img input button td select textarea

块元素:独占一行,默认继承父元素的宽度,高度为0
例外:p,h不能放块标签

BFC 块级格式上下文

BFC 计算BFC会计算float高度——浮动塌陷
BFC 内部margin重叠——外部创建bfc,形成两个bfc
BFC 内部不会与float盒子重叠——自适应布局

创建BFC:
(1)position:absolute/fixed(脱离文档流)
(2)float:left/right(脱离文档流)
(3)overflow:hidden/auto/scroll
(4)display:inline-block/inline-grid/inline-table/table-caption/table-cell/flex/table/grid

margin 重叠

同一个bfc内相邻块级元素垂直marin只会取较大值

解决: 1. 子元素脱离当前bfc,底部元素设置float,absolute/fixed
      2. 外层父元素添加padding
      3. 子元素增加一层bfc父元素

浮动(高度)塌陷

原因:在文档流中,父元素的高度默认是被子元素撑开的
子元素设置浮动无法撑起父元素的高度,且此时父元素未设置高度,导致父元素的高度塌陷
,父元素下的所有元素都会向上移动,造成布局错位

clear:both
overflow:hidden
父级元素添加高度

选择器优先级

!important
内联样式
id 选择器
伪类选择器 类选择器 属性选择器[attribute]
伪元素 before after  元素选择器
关系选择器+ >  统配选择器 *
继承
默认

水平垂直居中

子元素添加:
单行文本:line-height:num          text-align:center(非行内元素)

多行文本垂直居中:
父元素:line-height:height,height:number
子元素:vertical-align:middle(仅行内块元素),line-height:num

宽高固定,子元素添加:
	子元素宽高已知absolute; top,left:50%;   	 margin-left,margin-top:- (父元素50%宽高)
	子元素宽高固定absolute; top,left:num(一般设置0)   margin:auto
	无限制absolute;top,left:50%; transform:translate(-50%,-50%)

移动端,父元素添加,flex
    justify-content: center;
    align-items: center;

grid
    align-self: center;
    justify-self: center;

回流(重排)和重绘

回流:当render tree中尺寸,布局,隐藏等改变需要重新构建render tree。这就称为回流(reflow)。  回流必重绘
重绘:当render tree中的一些元素需要更新属性,而这些属性只是影响元素的外观,风格,而不会影响布局的

js

JS 对象常用方法

运算符: ??= null、undefined时赋值    &&= 为真时赋值     ||= 为假时赋值
date对象: getDate() getDay() getFullYear() getHours() getMinutes() getMonth()
setDate() setDay() setFullYear() setHours() setMinutes() setMonth() getTime()
Date.now() toJson() toLocalString() toLocalDateString() toLocalTimeString()

数组: fill[value,start,end) slice[) splice[第a个元素前,删除b个,添加元素] join(指定分隔符默认,)
pop() push() reverse() sort() unshift shift concat indexOf() lastIndexOf() includes() isArray()
toString()  from() filter() find() findIndex() every() some() reduceRight() reduce() map()
at(-1) flatMap() toSorted() toSpliced() toReversed() flat()

字符串: split(指定分隔符,指定返回数组length,满足条件返回) match replace replaceAll() search匹配单个下标,无值返回-1
padEnd(num,symbol) padStart(num,symbol) indexOf() lastIndexOf() includes() link() concat()
trim()去除两边空字符 trimStart()去除开始的空字符 trimEnd()去除开始的空字符 trimLeft trimRight
startWith()判断是否以指定字符串开始 endWith() repeat(num)  toLowerCase()  toUpperCase()
a.localeCompare(b)0 相同 1 a在b前 -1 a在b后 normalize('NFC')
String.fromCharCode() charAt(num) charCodeAt(num)

数学: random() ceil()上舍入 floor()下舍入 round()四舍五入 pow(x,y)x的y次方 min() max() abs()
toPrecision()返回位数 toFixed(13)返回小数点后指定位数,超出按照四舍五入计算

global: Number() String()  isNaN() eval() isFinite() parseInt() parseFloat() atob btoa 转为base64和编码base64
escape()编码 unescape()解码             字符串编解码,不用于url
decodeURI()解码 encodeURI()编码         编码整个url
decodeURIComponent()  encodeURIComponent()        编码范围更广,编码参数

Object: create(a)创建a的原型对象 is() keys() values() entries() fromEntries()

URLSearchParams: new URLSearchParams('') has get getAll append set delete toString entries keys

window 对象

剪切板navigator.clipboard.writeText write read readText
document.execCommand('copy')

innerWidth innerHeight outWidth outHeight包含工具栏,滚动栏
pageXOffset pageYOffset页面左上角滚动栏卷走的px
screenX screenY screenLeft screenTop窗口相对屏幕的坐标
sessionStorage localStorage.setItem(a,b) getItem(a) removeItem(a)
confirm带有确认,取消提示框 alert prompt()可输入提示框
clearInterval clearTimeout setTimeout setInterval	open(url,name打开方式) close
getComputedStyle()仅支持读,读取样式是最终样式  getSelection()获得选中内容
matchMedia(查询字符串) .matches媒体查询 addListener(fn)经停监听媒体查询变化 	removeListener(fn)
moveBy()移动指定坐标 moveTo()  resizeBy() resizeTo() scrollBy() scrollTo()
print()打印 stop()停止加载
跨源通信otherWindow.postMessage(data, [],transfer)otherWindow其他窗口引用:
window.open窗口对象、iframe的contentWindow属性,data将要发送的数据,[]指定窗口url,transfer对象所有权转移给接收方

location:hash返回#后  host hostname返回主机和端口  href返回url search返回查询部分
assign()载入新文档 reload()重载页面 replace()替换页面,不可返回前一个页面

(window).document 对象

addEventListener() removeEventListener()
anchors返回当前页面锚节点数组,必须包含name属性才会加入数组
baseURI domain返回域名  URL=location.href title cookie() lastModified最后一次修改

creatAttribute()属性节点 creatComment()注释节点 createElement()元素节点  creatDocumentFragment()虚拟对象节点
createTextNode()文本节点 getAttribute()返回属性值 getAttributeNode()返回属性节点
hasAttribute()判断存在指定属性 hasAttributes()判断存在属性 hasChildNodes()判断存在子节点
removeAttribute(name) removeAttributeNode() removeChild()
replaceChild(new,old) setAttribute(name,value) setAttributeNode()

appendChild()添加到最后的子节点 insertBefore(newNode,oldNode)添加到老节点之前
attributes属性集合 childNodes子节点(所有类型)集合 children子元素节点集合
parentNode firstChild lastChild cloneNode(true克隆子孙节点)
nextSibling返回下一个同级节点 nextElementSibling只返回元素节点
previousSibling前一个同级节点 previousElementSibling只返回元素节点
a.isEqualNode(b)ab两个节点相等 a.isSameNode(b)ab同一个节点

querySelector() querySelectorAll()用css选择器,性能更差  getElementBy()
nodeName className id innerHTML所有节点 textContent获取文本节点 classlist.contains toggle remove add

attributes属性集合:name value length

ES6 新特性

解构赋值 let[a,b,c]=[56,56,6]
字符串扩展
	双字节	'\uxxxx'  \u0000~\uFFFF
	完整unicode	'\u{}'

数组扩展 flat(n)
	from将类数组对象和可遍历对象(set,map)转为数组 of将值转化为数组  for of
    键值对遍历entries() 键名遍历keys() 键值遍历values() 返回遍历器对象Iterator

遍历器Iterator:为各种数据结构(set,map,array,object)提供统一的接口,主要供for of使用
创建指针对象,调用next指向数据结构,不能链式 返回对象{value,done}
	自定义迭代器[Symbol.iterator](){}
生成器generator: function* a(){yield}
	第一次调用next开始执行生成器,传参无效
	yield* 能迭代可迭代对象,相当于对象添加一个迭代器
	自定义生成器的迭代器 *[Symbol.iterator](){}
使用场合:解构赋值 ...  for of  array.from() promise.all() promise.race()

对象扩展 属性简写:变量写在{}里面,属性名=变量名 属性值=变量值  解构赋值{...}
		方法简写:a:function(){}  a(){}
		super只能用在对象的简写方法中,指向当前对象的原型对象中,常用于类的继承

对象新方法 Object.is(a,b) 与===不同NaN=NaN -0!=+0
		  Object.assign(a,b,c...) 对象合并 b,c...复制到a 浅拷贝,处理数组会覆盖
   		  键值对遍历entries() 键名遍历keys() 键值遍历values() 返回数组
		  fromEntries()键值对数组转为对象

map([[][]]) 键名可定义为对象,不再局限于字符串 set() get() delete() has() clear() size ,也可以直接接受数组创建
set对象 类数组对象,值不可重复,自动过滤重复元素,也可以直接接受数组创建add delete clear has size
模块import from只读,对象可改 export default可不需要了解模块具体细节,默认加载,此时import可起任意名

类的方法定义在prototype,包括构造函数 set  get设置存取值函数
静态方法,属性不会被实例继承,但可以被类继承,只能直接通过类调用
私有方法和属性在前面加上#,且变量无需关键词

类的继承constructor中显示写法必须先使用super,调用super后才能用this,再用this改变指向
super作为函数使用时,super指向子类的构造函数,但代表的是父类的构造函数,只能用于构造函数
super作为对象使用时,指向父类,但this指向子类,无法调用父类的实例方法属性

父类a 子类b
b.prototype._proto_=a.prototype
b._proto_=a
因为继承实现基于setPrototypeOf=function(b.prototype,a.prototype){
b.prototype._proto_=a.prototype;
return b.prototype;
}

可继承原生构造函数boolean() array() number() string() date() function() object()

promise,async/await,generator
指数运算符**    扩展运算符...    模板字面量``   `a+${}+b`
新类型symbol('')唯一不会产生冲突
箭头函数没有原型,this指向定义时所在的对象,并且不能改变指向

解决回调地狱

promise  pending fullfilled rejected 状态不可逆
new Promise((resolve,reject)=>{}), reject(),resolve()状态改变,
会继续执行后续代码,代码不会直接结束 then(resolve,reject)返回新的promise实例,参数为上层promise对象返回值
catch=then(null,reject)
finally不管是什么状态都要执行,一般放在链式的最后,且不接受任何参数

Promise.all([]) 参数必须有iterator接口,参数全部resolve新实例状态变为fullfilled,参数实例返回值组成的数组传给回调,
或者第一个rejected新实例变为rejected,第一个reject参数实例的返回值传给回调
Promise.any 第一个resolve的实例返回值,或者所有参数rejected实例返回值组成的数组

Promise.race 第一个fullfilled或者rejected的实例,作为新实例的状态和返回值
Promise.allsettled 所有参数实例状态都改变才执行回调,并且新实例状态总是fullfilled,
回调接收参数是参数实例返回值(对象,包括状态属性,返回值属性)组成的数组

Promise.reject("a") === new Promise((resolve,reject)=>reject('a'));
Promise.resolve("a") === new Promise(resolve=>resolve('a'));

async/ await
await后面非promise对象基本等于同步操作(先执行async外部的同步代码,再执行内部代码)

任意一个状态变成reject,后续代码不再执行 await
解决方案
try {
await}
catch{}

const testAsync = async()=>{
return await Promise.reject("aaaa").catch((err)=>{return err})
}
testAsync().then((res)=>{
console.log("成功:",res)
}).catch((err)=>{
console.log("外部错误:",err)
})
此时必执行testAsync.then,因为错误过程已经在async内部处理,浏览器认为promise成功

typeof 和 instance of

基本数据类型:number,string,null,undefined,boolean(存放在栈内存中)
引用类型存放在堆内存中,实际上存放的是指向对象的地址
基本类型:number,boolean,string,object,null,undefined,symbol,bigint
typeof:number,boolean,string,function,object(null返回值),undefined,symbol, bigint
instance of:检测某个对象是不是另一个对象的实例,能判断object子类

防抖节流

用户操作会导致频繁触发事件,对dom操作,资源加载等,导致网页卡顿甚至崩溃
绑定触发高频率的事件,scroll,mousemove,resize,mousedown,keyup,希望降低触发频率
防抖:事件在n秒内执行一次,如果单位时间内又触发了事件,时间计数清零
    实时搜索,拖拽,窗口调整,页面滚动

节流:每隔n秒执行一次函数
    窗口调整,页面滚动,疯狂点击

深浅拷贝

浅拷贝:拷贝多份非数字型数据,改变一份数据,会同时改变其他数据
深拷贝:改变数据,不改变其他数据
实现:JSON.parse(JSON.stringify(obj,function,添加缩进))
JSON方法限制: Date,undefined,Regexp,function,symbol,map,set不能正确拷贝

stringify(obj,(key,value)=>{console.log(`键名${key} 键值${value}`) return value} || ['要转换的对象'])
parse(str,(key,value)=>{return key==='' ? value+'拼接值' : value})

递归

for in会迭代原型链的属性
数组返回数组下标(键值)
适合对象

for of ES6新特性,只会迭代对象本身的属性
返回数组元素
适合数组
用于对象需要
Object.key(arr)(键值)
Object.values(arr)(对象值)

模块化

引入 js 脚本太多,重名,变量污染,可能存在依赖关系,需要按顺序加载 模块化就是一种解决问题的方案,一个模块实现特定功能的文件

1.闭包和命名空间
2.CommonJs(服务器):require引入指定模块,module暴露内容
3.AMD和RequireJS(浏览器)
4.CMD和SeaJs
5.es6模块化:
	 export 变量名
     import * as(重命名) from src

事件流

接收事件的顺序,分为三个阶段
事件捕获阶段(从父元素传递到子元素)
处于目标阶段(绑定事件的那个元素)
事件冒泡阶段(子元素传递到父元素)

js 事件循环机制,宏任务微任务

事件循环:
1.主线程上先执行同步任务
2.出现异步任务会按顺序放入"任务队列"(在子线程中执行异步任务)
3.一旦本轮同步任务执行完毕,系统就会读取执行"任务队列"
4.一直重复,也就是常说的Event Loop(事件循环)

宏任务: script,settimeout,setinterval,setImmediate,requestAnimationFrame

微任务: 当前宏任务执行结束后立即执行的任务。 promise,async/await,MutationObserver
process.nextTick(node.js):在当前任务队列执行完,第一个执行,优先级高的异步任务

dom0 级事件 dom2 级事件

0级:同一个元素绑定多个事件,只会绑定最后一个事件,只能在事件冒泡阶段触发
不支持冒泡的事件load unload scroll resize blur focus mouseleave mouseenter
取消冒泡:stopPropagation() cancelBuble=true
绑定事件:dom.onclick
解除绑定:dom.onclick=null

2级:可以监听多个事件,只有2级DOM有完整的事件流
绑定:dom.addEventListener(type,function,false)
解除绑定:dom.removeEventListener(type,function,false)
true:捕获阶段调用;false:冒泡阶段调用

原型链

指向原型__proto__ 指向原型构造函数constructor 指向函数原型对象prototype
在JavaScript中通过__proto__ 指向prototype,直到指向Object对象为止,就形成了一个原型指向的链条,称之为原型链。
当我们访问对象的一个属性或方法时,它会先在对象自身中寻找,没有则会去原型对象中寻找,
直到找到Object对象的原型,如果在Object原型(null)中依然没有找到,则返回undefined。

闭包,内存泄漏

立即执行函数(function(a,b){}(传递的参数1,2,3...))

访问函数内部变量
利用垃圾回收机制,被引用的变量不会被回收,所以会造成内存泄漏

垃圾回收机制: 引用计数 标记清除

作用域链,变量提升

变量提升优先级小于函数提升 var
每次进入一个新的执行环境,都会创建一个用于搜索变量和函数的作用域链,搜索是一级一级往上搜索,一旦找到不再搜索
变量提升:使用了在下面定义的变量,把变量提升到函数顶部,但使用时变量值为undefined
函数提升:和变量提升类似,但是只有声明会被提升,函数表达式,构造不会被提升

js 多线程 通信协议

new Worker(js file path)
只把耗时的操作写到worker线程里

http三次握手,只能由客户端发起,做不到主动推送信息

HTML5 WebSocket:HTML5 开始提供的全双工通讯的协议,握手阶段采用http协议,无同源限制
WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据
new WebSocket(url, [protocol] )

bind,call,apply 的区别

第一个参数都是this的指向对象
bind 返回值是函数,参数和call类似
call
apply 参数是数组

原生 ajax

XMLHttpRequest Level 1

let ajax = new XMLhttpRequest();
ajax.open(get/post,'url',false);
//模拟表单提交,配置请求头
//ajax.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
ajax.send();
ajax.onreadstatechange()=function(){
if(ajax.readyState==4 && ajax.status==200)
return ajax.reponeseText;
	   ajax.reponseXML
}

XMLHttpRequest Level 2

formData()表单数据序列化
数据填充
let test=new formData().append(name,value)相当于表单字段名称和该字段的值
formData(document.form[num])
ajax.send(test);

超时
超时设置ajax.timeout=1000;
超时事件ajax.ontimeout=function()

进度事件
loadstart:在接收到响应的第一个字节时触发。
progress:在接收响应期间反复触发。
error:在请求出错时触发。
abort:在调用 abort()终止连接时触发。
load:在成功接收完响应时触发。  可替代readyStateChange,不用检查readyState
loadend:在通信完成时,且在 error、abort 或 load 之后触发。

Fetch

FileReader 转存 base64 FileReader.readAsArrayBuffer() FileReader.readAsBinaryString() FileReader.readAsDataURL() FileReader.readAsText()

  能够执行 XMLHttpRequest 对象的所有任务,但更容易使用,接口也更现代化,能够在
Web 工作线程等现代 Web 工具中使用,Fetch API 必须是异步

fetch(url,(init)); //get请求
自定义选项(init)
body 指定请求内容
headers 指定请求头
integrity 强制子资源完整性
method 请求方法
mode 请求模式 cors允许遵守CORS协议的跨源请求 no-cors允许不需要发送预检请求的跨源请求 same-origin不允许跨域
redirect 处理重定向方式
signal

1. 发送 JSON 数据
可以像下面这样发送简单 JSON 字符串:
let payload = JSON.stringify({
 foo: 'bar'
});
let jsonHeaders = new Headers({
 'Content-Type': 'application/json'
});
fetch('/send-me-json', {
 method: 'POST', // 发送请求体时必须使用一种 HTTP 方法
 body: payload,
 headers: jsonHeaders
});

2. 在请求体中发送参数
因为请求体支持任意字符串值,所以可以通过它发送请求参数:
let payload = 'foo=bar&baz=qux';
let paramHeaders = new Headers({
 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
});
fetch('/send-me-params', {
 method: 'POST', // 发送请求体时必须使用一种 HTTP 方法
 body: payload,
 headers: paramHeaders
});

3. 发送文件
因为请求体支持 FormData 实现,所以 fetch()也可以序列化并发送文件字段中的文件:
let imageFormData = new FormData();
let imageInput = document.querySelector("input[type='file']");
imageFormData.append('image', imageInput.files[0]);
fetch('/img-upload', {
 method: 'POST',
 body: imageFormData
});
这个 fetch()实现可以支持多个文件:
let imageFormData = new FormData();
let imageInput = document.querySelector("input[type='file'][multiple]");
for (let i = 0; i < imageInput.files.length; ++i) {
 imageFormData.append('image', imageInput.files[i]);
}
fetch('/img-upload', {
 method: 'POST',
 body: imageFormData
});


File.prototype == Blob

const reader = new FileReader();
reader.addEventListener(
"load",
() => {
    // 将图像文件转换为 Base64 字符串
    preview.src = reader.result;
},
false,
);
reader.readAsDataURL(file);

4. 加载 Blob 文件
Fetch API也能提供 Blob 类型的响应,而 Blob 又可以兼容多种浏览器 API。一种常见的做法是明确将
图片文件加载到内存,然后将其添加到 HTML图片元素。为此,可以使用响应对象上暴露的 blob()方法。
这个方法返回一个期约,解决为一个 Blob 的实例。然后,可以将这个实例传给 URL.createObjectUrl()
以生成可以添加给图片元素 src 属性的值:
const imageElement = document.querySelector('img');
fetch('my-image.png')
 .then((response) => response.blob())
 .then((blob) => {
 imageElement.src = URL.createObjectURL(blob);
 URL.revokeObjectURL(objectURL)
 });

5. 中断请求
Fetch API 支持通过 AbortController/AbortSignal 对中断请求。调用 AbortController.
abort()会中断所有网络传输,特别适合希望停止传输大型负载的情况。中断进行中的 fetch()请求会
导致包含错误的拒绝。
let abortController = new AbortController();
fetch('wikipedia.zip', { signal: abortController.signal })
// 10 毫秒后中断请求
setTimeout(() => abortController.abort(), 10);
// 已经中断

 fetch('https://foo.com')
 .then((response) => response.text())

 fetch('https://foo.com/foo.json')
 .then((response) => response.json())

web Socket

Web Socket使用了自定义协议,所以 URL方案(scheme)稍有变化:不能再使用 http://或 https://,
而要使用 ws://和 wss://  服务器端可以主动推送信息
必须给 WebSocket 构造函数传入一个绝对 URL。同源策略不适用于 Web Socket,因此可以打开到任意站点的连接
readyState
 WebSocket.OPENING(0):连接正在建立。
 WebSocket.OPEN(1):连接已经建立。
 WebSocket.CLOSING(2):连接正在关闭。
 WebSocket.CLOSE(3):连接已经关闭。

message:服务器向客户端发送消息触发
open:在连接成功建立时触发。
error:在发生错误时触发。连接无法存续。
close:在连接关闭时触发。
WebSocket 对象不支持 DOM Level 2 事件监听器,因此需要使用 DOM Level 0 风格的事件处理程
序来监听这些事件



let webSocket = null;
export const contactSocket = () => {
  if ("WebSocket" in window) {
    webSocket = new WebSocket("ws://192.168.1.100:8888/");
    webSocket.onopen = function () {
      // 发送消息
      webSocket.send('连接成功!')
    };
    webSocket.onmessage = function (evt) {
      var received_msg = evt.data;
      console.log("接受消息:" + received_msg);
    };
    webSocket.onclose = function () {
      console.log("连接关闭!");
    };
  }
}

正则表达式

search(//) match(//g) replace(/()/,’$1’) split

exec 检索字符串中指定的值,返回值,确定匹配位置
test 返回true false

优先级:\ > 圆括号和方括号 > 限定符 > 其他字符
修饰符: g全局 i忽略大小写 m多行匹配^$能匹配\n   s使.能匹配\n y下次匹配在lastIndex位置开始

匹配单个普通字符:
[ABC] 匹配括号内字符
[^ABC] 仅不匹配括号内字符
[A-Z] 匹配括号内区间的字符
\w  匹配合法变量字符(字母,数字,下划线,但不包括$)
\W  ^\w

匹配特殊字符:
除[]外都可以用[string]匹配
\[   \]

匹配非打印字符:

\f 匹配换页符
\t 匹配制表符
\r 匹配回车符
\n 匹配换行符
\\ 匹配反斜杠
\s 匹配空白字符
\S 匹配非空白字符

匹配限定符:
* 匹配前面的表达式0 || n, ==={0,}      贪婪匹配
+ 匹配前面的表达式1 || n, ==={1,}      贪婪匹配
? 匹配前面的表达式0 || 1, ==={0,1}
{n} 匹配确定的n次
{n,} 至少匹配n次     贪婪匹配
{n,m} 匹配[n,m]次

定位符:
^ 匹配输入字符串开始的位置
$ 匹配输入字符串结尾的位置

元字符:
. 任意字符
\s 匹配任何空格字符 === [ \f\n\r\t\v]
\S 匹配非空格字符 ===  [^ \f\n\r\t\v]
\b 匹配单词边界 'er\b' 可以匹配"never" 中的 'er',但不能匹配 "verb" 中的 'er'
\B 匹配非单词边界 'er\B' 能匹配 "verb" 中的 'er',但不能匹配 "never" 中的 'er'
| 或者
(?=) exp1(?=exp2):查找 exp2 前面的 exp1
(?!)  exp1(?!exp2):查找后面不是 exp2 的 exp1
(?<=) (?<=exp2)exp1:查找 exp2 后面的 exp1
(?<!) (?<!exp2)exp1:查找前面不是 exp2 的 exp1

vue,react

虚拟 DOM

避免频繁操作 DOM

跨平台渲染,服务器渲染 、小程序、原生应用都使用了虚拟 DOM

虚拟 DOM 可以维护程序的状态,跟踪上一次的状态

对象映射虚拟节点包含标签名,标签属性,标签子节点属性

<ul id="list">
    <li class="item">哈哈</li>
    <li class="item">呵呵</li>
    <li class="item">嘿嘿</li>
</ul>

let oldVDOM = { // 旧虚拟DOM
        tagName: 'ul', // 标签名
        props: { // 标签属性
            id: 'list'
        },
        children: [ // 标签子节点
            {
                tagName: 'li', props: { class: 'item' }, children: ['哈哈']
            },
            {
                tagName: 'li', props: { class: 'item' }, children: ['呵呵']
            },
            {
                tagName: 'li', props: { class: 'item' }, children: ['嘿嘿']
            },
        ]
    }

vue2 diff 算法

对比虚拟 dom,找出更改的虚拟 dom,只更新修改虚拟 dom 对应的真实 dom,边更新边修改

实现:整体广度优先算法,同层进行比较(跨层级的位置变化,创建节点和删除节点的操作),同层遍历按照深度优先算法比较。

两端对比,定义指针分别指向新旧虚拟节点,新旧节点两两比较,如果相同说明可以复用直接更新或者移动节点

不同去旧的虚拟节点查找是否存在新节点,存在移动旧的虚拟dom,不存在直接创建新节点(性能考虑,旧节点放入map中,减少查找时间)

新节点指针相交或旧节点指针相交(说明遍历完旧或者新节点),退出循环

多数情况下不会同时遍历完新旧节点,所以需要做最后的处理
if是新节点相交,说明旧节点没处理完,所以需要把剩余节点删除
else是旧节点相交,说明新节点没处理完,直接插入剩余的新节点到旧的尾指针

vue3 diff 算法

和vue2一样只对比同层级的虚拟dom节点

定义指针指向新旧虚拟节点,再定义两个指针指向新旧尾节点

预处理:
定义一个循环,if新旧头节点相同更新,移动头指针,else退出循环
定义一个循环,if新旧尾节点相同更新,移动新旧尾指针,else退出循环

if 头指针>新的尾指针,说明新节点处理完成,剩余旧节点删除
if 头指针>旧的尾指针,说明旧节点处理完成,插入剩余新节点到旧的尾指针

都不相等,说明都没处理完,做乱序处理
将剩余未处理新节点加入到map中,提高后续查找性能
然后定义一个和未处理新节点一样大小的数组,并初始化为-1
遍历旧节点,if map中存在,说明旧节点存在,数组对应位置赋值为当前旧节点的索引,else 说明未来这个节点已经不存在,直接删除

然后找到数组的最长递增子序列,尽可能减少移动dom节点

最后遍历数组
if值为-1,说明节点不可复用,直接在当前位置新增
if值为包含在最长递增子序列,无需操作
else移动旧的虚拟节点到当前位置

例子

老的 children:[ a, b, c, d, e, f, p, g ]
新的 children:[ a, b, f, c, d, e, h, g ]
预处理后节点: [c, d, e, f, p]
              [ f, c, d, e, h ]
source: [-1,-1,-1,-1,-1]
改变source:[ 5, 2, 3, 4, -1 ]
最长递增子序列:[2,3,4]   maxChildArr:[1,2,3]
最终遍历: 遍历 source, if item===-1,直接在old尾部新增,if include(最长递增子序列),不需要操作,else插入到对应位置

react diff 算法(递增法)

1.跨层级的位置变化,则是创建节点和删除节点的操作

2.对比当前同层的虚拟节点是否为同一种类型的标签 patch,不同直接替换 replace

3.同层级节点:

移动:先遍历new节点,找到new在old的位置,记录上一节点的位置与当前遍历节点比较,if(preIndex<curIndex)不需要移动,否则需要移动位置
新增:定义标记变量find=false,在old中找到和new相同的key,find=true,遍历完old还为flase,新增节点
删除:移动新增完(遍历新旧节点),遍历old,找出new节点中不存在的并移除

源码

function reactDiff(prevChildren, nextChildren, parent) {
    let lastIndex = 0
    for (let i = 0; i < nextChildren.length; i++) {
        let nextChild = nextChildren[i],
            find = false;
        for (let j = 0; j < prevChildren.length; j++) {
            let prevChild = prevChildren[j]
            if (nextChild.key === prevChild.key) {
                find = true
                patch(prevChild, nextChild, parent)
                if (j < lastIndex) {
                    // 移动到前一个节点的后面
                    let refNode = nextChildren[i - 1].el.nextSibling;
                    parent.insertBefore(nextChild.el, refNode)
                } else {
                    // 不需要移动节点,记录当前位置,与之后的节点进行对比
                    lastIndex = j
                }
                break
            }
        }
        if (!find) {
            // 插入新节点
            let refNode = i <= 0
                            ? prevChildren[0].el
                            : nextChildren[i - 1].el.nextSibling
            mount(nextChild, parent, refNode);
        }
    }
    for (let i = 0; i < prevChildren.length; i++) {
        let prevChild = prevChildren[i],
            key = prevChild.key,
            has = nextChildren.find(item => item.key === key);
        if (!has) parent.removeChild(prevChild.el)
    }
}

react fiber

在 Fiber 诞生之前,React 处理一次 setState()(首次渲染)时会有两个阶段:

调度阶段(Reconciler):这个阶段React用新数据生成新的 Virtual DOM,遍历 Virtual DOM,然后通过 Diff 算法,快速找出需要更新的元素,放到更新队列中去。
渲染阶段(Renderer):这个阶段 React 根据所在的渲染环境,遍历更新队列,将对应元素更新。在浏览器中,就是更新对应的 DOM 元素。

对于复杂组件,层次深的组件,非常影响性能

fiber缓解性能问题

获取浏览器控制权: requestIdleCallback 和 requestAnimationFrame


加入了更新进入时暂停,中止或重复工作的能力和为不同类型的更新分配优先级的能力。一次更新分散在多次时间片中,另外, 在浏览器空闲的时候, 也可以继续去执行未完成的任务, 充分利用浏览器每一帧的工作特性。